package com.dl698.asn1.axdr;

import com.dl698.util.ReverseByteArrayInputStream;
import com.dl698.util.ReverseByteArrayOutputStream;

import java.io.IOException;

/**
 * AXDR长度类型
 * 实现长度值的编解码
 * 
 * @author wind
 * @version 1.1.1
 */
public class AxdrLength implements AxdrType {

    private int length;

    /**
     * 构造函数
     * 
     * @param length 长度值
     */
    public AxdrLength(int length) {
        this.length = length;
    }

    /**
     * 编码长度（静态方法）
     * 
     * @param output 输出流
     * @param length 长度值
     * @return 编码字节数
     * @throws IOException IO异常
     */
    public static int encodeLength(ReverseByteArrayOutputStream output, int length) throws IOException {
        int codeLength = 0;
        if (length == 0) {
            output.write(0);
            codeLength++;
        } else {
            int lengthOfLength = 0;
            for (int i = 0; (length >> (8 * i)) != 0; i++) {
                output.write((length >> (8 * i)) & 0xFF);
                lengthOfLength++;
                codeLength++;
            }
            if (length >= 128) {
                output.write((lengthOfLength & 0xFF) | 0x80);
                codeLength++;
            }
        }
        return codeLength;
    }

    /**
     * 编码长度到字节数组
     * 
     * @param length 长度值
     * @return 编码后的字节数组
     */
    public byte[] encodeLengthBuf(int length) {
        if (length == 0) {
            return new byte[] { 0 };
        } else {
            int lengthOfLength = 1;
            while ((length >> (8 * lengthOfLength)) != 0) {
                lengthOfLength++;
            }

            int offset = 0;
            byte[] buffer;

            if (length > 255) {
                buffer = new byte[lengthOfLength + 1];
                buffer[0] = (byte) (lengthOfLength | 0x80);
                offset++;
            } else {
                buffer = new byte[lengthOfLength];
            }

            for (int i = 0; i < lengthOfLength; i++) {
                buffer[offset + i] = (byte) (length >> (8 * (lengthOfLength - 1 - i)));
            }

            return buffer;
        }
    }

    @Override
    public int decode(ReverseByteArrayInputStream input) {
        try {
            int codeLength = 0;
            length = input.read();
            codeLength++;

            if ((length & 0x80) == 0x80) {
                int encodedLength = length ^ 0x80;
                codeLength += encodedLength;
                length = 0;

                byte[] byteCode = new byte[encodedLength];
                if (input.readOffset(byteCode, 0, encodedLength) < encodedLength) {
                    throw new RuntimeException("Error Decoding AxdrLength");
                }

                for (int i = 0; i < encodedLength; i++) {
                    length |= (byteCode[i] & 0xFF) << (8 * (encodedLength - i - 1));
                }
            }

            return codeLength;
        } catch (IOException e) {
            throw new RuntimeException("Decode error", e);
        }
    }

    @Override
    public int encode(ReverseByteArrayOutputStream output) {
        try {
            return encodeLength(output, length);
        } catch (IOException e) {
            throw new RuntimeException("Encode error", e);
        }
    }

    /**
     * 获取长度值
     * 
     * @return 长度值
     */
    public int getValue() {
        return length;
    }

    /**
     * 设置长度值
     * 
     * @param length 长度值
     */
    public void setValue(int length) {
        this.length = length;
    }

    @Override
    public String toString() {
        return String.valueOf(length);
    }
}